/**
 * Copyright 2006-2015 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mybatis.generator.codegen.mybatis3.model;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.codegen.AbstractJavaGenerator;
import org.mybatis.generator.internal.util.JavaBeansUtil;

import java.util.ArrayList;
import java.util.List;

import static org.mybatis.generator.internal.util.messages.Messages.getString;

/**
 * @author Jeff Butler
 */
public class DTOGenerator extends AbstractJavaGenerator {

    public DTOGenerator() {
        super();
    }

    @Override
    public List<CompilationUnit> getCompilationUnits() {
        FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();
        progressCallback.startTask(getString("Progress.8", table.toString())); //$NON-NLS-1$

        String pakkage = introspectedTable.calculateJavaModelPackage();
        String requestClassName, responseClassName;
        StringBuilder sb = new StringBuilder();
        sb.append(pakkage);
        sb.append(".dto.request.");
        sb.append(introspectedTable.getFullyQualifiedTable().getDomainObjectName());
        sb.append("Request");
        requestClassName = sb.toString();

        sb.setLength(0);
        sb.append(pakkage);
        sb.append(".dto.response.");
        sb.append(introspectedTable.getFullyQualifiedTable().getDomainObjectName());
        sb.append("Response");
        responseClassName = sb.toString();

        List<CompilationUnit> answer = new ArrayList<CompilationUnit>();

        genertorDTOJavaClass(answer, requestClassName);
        genertorDTOJavaClass(answer, responseClassName);

        return answer;
    }

    private void genertorDTOJavaClass(List<CompilationUnit> answer, String className) {
        Plugin plugins = context.getPlugins();
        CommentGenerator commentGenerator = context.getCommentGenerator();

        FullyQualifiedJavaType superClassType = new FullyQualifiedJavaType("org.tianyun.cloud.common.dto.BaseDTO");

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(className);
        TopLevelClass topLevelClass = new TopLevelClass(type);
        topLevelClass.setVisibility(JavaVisibility.PUBLIC);
        topLevelClass.setSuperClass(superClassType);
        topLevelClass.addImportedType(superClassType);
        commentGenerator.addJavaFileComment(topLevelClass);

        Field serialVersionUID = new Field("serialVersionUID", new FullyQualifiedJavaType("long"));
        serialVersionUID.setVisibility(JavaVisibility.PRIVATE);
        serialVersionUID.setFinal(true);
        serialVersionUID.setStatic(true);
        serialVersionUID.setInitializationString("1L");
        serialVersionUID.addJavaDocLine("/**");
        serialVersionUID.addJavaDocLine(" * serialVersionUID");
        serialVersionUID.addJavaDocLine(" */");
        topLevelClass.addField(serialVersionUID);

        List<IntrospectedColumn> introspectedColumns = getColumnsInThisClass();

        FullyQualifiedJavaType apiModel = new FullyQualifiedJavaType("io.swagger.annotations.ApiModel");
        FullyQualifiedJavaType apiModelProperty = new FullyQualifiedJavaType("io.swagger.annotations.ApiModelProperty");
        topLevelClass.addImportedType(apiModel);
        topLevelClass.addImportedType(apiModelProperty);
        topLevelClass.addAnnotation("@ApiModel");

        StringBuilder sb = new StringBuilder();
        for (IntrospectedColumn introspectedColumn : introspectedColumns) {
            sb.setLength(0);
            sb.append("@ApiModelProperty(value=\"");
            sb.append(introspectedColumn.getRemarks());
            sb.append("\"");
            if (!introspectedColumn.isNullable()) {
                sb.append(", required = true");
            }
            sb.append(")");

            FullyQualifiedJavaType fqjt = introspectedColumn.getFullyQualifiedJavaType();
            String property = introspectedColumn.getJavaProperty();
            Field field = new Field();
            field.setVisibility(JavaVisibility.PRIVATE);
            field.setType(fqjt);
            field.setName(property);
            field.addAnnotation(sb.toString());
            if (plugins.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, Plugin.ModelClassType.BASE_RECORD)) {
                topLevelClass.addField(field);
                topLevelClass.addImportedType(field.getType());
            }

            Method method = new Method();
            method.setVisibility(JavaVisibility.PUBLIC);
            method.setReturnType(fqjt);
            method.setName(JavaBeansUtil.getGetterMethodName(property, fqjt));

            sb.setLength(0);
            sb.append("return "); //$NON-NLS-1$
            sb.append(property);
            sb.append(';');
            method.addBodyLine(sb.toString());
            if (plugins.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, Plugin.ModelClassType.BASE_RECORD)) {
                topLevelClass.addMethod(method);
            }
            if (!introspectedTable.isImmutable()) {
                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setName(JavaBeansUtil.getSetterMethodName(property));
                method.addParameter(new Parameter(fqjt, property));

                sb.setLength(0);
                if (JavaBeansUtil.isTrimStringsEnabled(context) && introspectedColumn.isStringColumn()) {
                    sb.append("this."); //$NON-NLS-1$
                    sb.append(property);
                    sb.append(" = "); //$NON-NLS-1$
                    sb.append(property);
                    sb.append(" == null ? null : "); //$NON-NLS-1$
                    sb.append(property);
                    sb.append(".trim();"); //$NON-NLS-1$
                    method.addBodyLine(sb.toString());
                } else {
                    sb.append("this."); //$NON-NLS-1$
                    sb.append(property);
                    sb.append(" = "); //$NON-NLS-1$
                    sb.append(property);
                    sb.append(';');
                    method.addBodyLine(sb.toString());
                }
                if (plugins.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable, Plugin.ModelClassType.BASE_RECORD)) {
                    topLevelClass.addMethod(method);
                }
            }
        }

        if (context.getPlugins().modelBaseRecordClassGenerated(topLevelClass, introspectedTable)) {
            answer.add(topLevelClass);
        }
    }

    private boolean includePrimaryKeyColumns() {
        return !introspectedTable.getRules().generatePrimaryKeyClass() && introspectedTable.hasPrimaryKeyColumns();
    }

    private boolean includeBLOBColumns() {
        return !introspectedTable.getRules().generateRecordWithBLOBsClass() && introspectedTable.hasBLOBColumns();
    }

    private List<IntrospectedColumn> getColumnsInThisClass() {
        List<IntrospectedColumn> introspectedColumns;
        if (includePrimaryKeyColumns()) {
            if (includeBLOBColumns()) {
                introspectedColumns = introspectedTable.getAllColumns();
            } else {
                introspectedColumns = introspectedTable.getNonBLOBColumns();
            }
        } else {
            if (includeBLOBColumns()) {
                introspectedColumns = introspectedTable.getNonPrimaryKeyColumns();
            } else {
                introspectedColumns = introspectedTable.getBaseColumns();
            }
        }

        return introspectedColumns;
    }

}
